@link-assistant/web-capture 1.7.24 → 1.7.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/src/extract-images.js +15 -5
- package/tests/unit/extract-images.test.js +29 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @link-assistant/web-capture
|
|
2
2
|
|
|
3
|
+
## 1.7.26
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 112f2f9: Fix `stripBase64Images` (used by `--keep-original-links`) dropping every base64 image with empty alt text instead of leaving a visible placeholder. Google Docs HTML exports emit `<img alt="" src="data:image/png;base64,...">` for every image, so the previous behaviour silently deleted all images from the rendered markdown. Empty-alt now renders as `![]()` (a valid empty image reference); non-empty alt continues to render as `*[image: <alt>]*`.
|
|
8
|
+
|
|
9
|
+
## 1.7.25
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 024cb45: Fix `extractAndSaveImages` / `extractBase64ToBuffers` silently dropping base64 images when the markdown image is followed by a title attribute (e.g. ``). The base64 payload regex used `[^)]+`, which greedily included the trailing ` ""` and made `Buffer.from()` produce a decoded buffer that no longer matched the original image. The pattern now restricts the payload to base64 alphabet characters and matches the optional trailing markdown title separately so the title cannot leak into the payload.
|
|
14
|
+
|
|
3
15
|
## 1.7.24
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/package.json
CHANGED
package/src/extract-images.js
CHANGED
|
@@ -2,8 +2,11 @@ import { createHash } from 'crypto';
|
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
|
|
5
|
+
// Capture groups: alt text, mime subtype, base64 payload. A trailing
|
|
6
|
+
// markdown title attribute (e.g. ``) is matched but discarded so
|
|
7
|
+
// the empty title cannot leak into the base64 payload.
|
|
5
8
|
const BASE64_IMAGE_REGEX =
|
|
6
|
-
/!\[([^\]]*)\]\(data:image\/(png|jpeg|jpg|gif|webp|svg\+xml);base64,([
|
|
9
|
+
/!\[([^\]]*)\]\(data:image\/(png|jpeg|jpg|gif|webp|svg\+xml);base64,([A-Za-z0-9+/=]+)(?:\s+"[^"]*")?\)/gi;
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* @param {string} markdown - Markdown content with data URI images
|
|
@@ -92,9 +95,16 @@ export function extractBase64ToBuffers(markdown, imagesDir = 'images') {
|
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
/**
|
|
95
|
-
* Strip base64 data URI images from markdown, leaving
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
+
* Strip base64 data URI images from markdown, leaving a visible placeholder.
|
|
99
|
+
* Used when keepOriginalLinks is enabled — base64 images have no original URL
|
|
100
|
+
* to restore, so we remove the heavy data URI but still leave a marker so the
|
|
101
|
+
* reader can see that an image was here.
|
|
102
|
+
*
|
|
103
|
+
* Non-empty alt becomes `*[image: <alt>]*`. Empty alt — common for Google Docs
|
|
104
|
+
* HTML exports, which emit `<img alt="" src="data:...">` for every image —
|
|
105
|
+
* becomes `![]()`, an empty markdown image reference that renderers still
|
|
106
|
+
* surface as a slot. Emitting `''` for empty-alt would silently delete every
|
|
107
|
+
* image in the document (see issue #117).
|
|
98
108
|
*
|
|
99
109
|
* @param {string} markdown - Markdown content with data URI images
|
|
100
110
|
* @returns {{markdown: string, stripped: number}}
|
|
@@ -105,7 +115,7 @@ export function stripBase64Images(markdown) {
|
|
|
105
115
|
BASE64_IMAGE_REGEX,
|
|
106
116
|
(_match, altText) => {
|
|
107
117
|
stripped++;
|
|
108
|
-
return altText ? `*[image: ${altText}]*` : '';
|
|
118
|
+
return altText ? `*[image: ${altText}]*` : '![]()';
|
|
109
119
|
}
|
|
110
120
|
);
|
|
111
121
|
return { markdown: updatedMarkdown, stripped };
|
|
@@ -130,6 +130,26 @@ describe('extract-images module', () => {
|
|
|
130
130
|
);
|
|
131
131
|
});
|
|
132
132
|
|
|
133
|
+
it('extracts a base64 image even when followed by an empty markdown title', () => {
|
|
134
|
+
// Google Docs HTML exports embed `<img title="" alt="" src="...">`, and
|
|
135
|
+
// the html2md pipeline can render that as ``. The base64
|
|
136
|
+
// extractor must still pull the image out cleanly so the rendered
|
|
137
|
+
// markdown does not carry multi-megabyte data URIs.
|
|
138
|
+
const md = `Hello.\n\n\n\nEnd.\n`;
|
|
139
|
+
const result = extractAndSaveImages(md, tmpDir);
|
|
140
|
+
expect(result.extracted).toBe(1);
|
|
141
|
+
expect(result.markdown).toMatch(/images\/image-[a-f0-9]+\.png/);
|
|
142
|
+
expect(result.markdown).not.toContain('data:image');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('extracts a base64 image with a non-empty markdown title', () => {
|
|
146
|
+
const md = `Hello.\n\n\n\nEnd.\n`;
|
|
147
|
+
const result = extractAndSaveImages(md, tmpDir);
|
|
148
|
+
expect(result.extracted).toBe(1);
|
|
149
|
+
expect(result.markdown).toMatch(/images\/image-[a-f0-9]+\.png/);
|
|
150
|
+
expect(result.markdown).not.toContain('data:image');
|
|
151
|
+
});
|
|
152
|
+
|
|
133
153
|
it('handles SVG data URIs', () => {
|
|
134
154
|
const svgContent =
|
|
135
155
|
'<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1"><rect fill="red" width="1" height="1"/></svg>';
|
|
@@ -184,12 +204,18 @@ describe('extract-images module', () => {
|
|
|
184
204
|
expect(result.markdown).not.toContain('data:image');
|
|
185
205
|
});
|
|
186
206
|
|
|
187
|
-
it('
|
|
188
|
-
|
|
207
|
+
it('leaves a visible placeholder when stripping a base64 image with empty alt', () => {
|
|
208
|
+
// Google Docs HTML exports emit `<img alt="" src="data:image/png;base64,...">`,
|
|
209
|
+
// which renders as ``. If stripping drops the markdown image
|
|
210
|
+
// entirely, every image in the doc vanishes from the output with no
|
|
211
|
+
// indication that anything was lost. Leave a visible placeholder so the
|
|
212
|
+
// reader can see that an image was here.
|
|
213
|
+
const md = `Hi.\n\n\n\nBye.\n`;
|
|
189
214
|
const result = stripBase64Images(md);
|
|
190
215
|
|
|
191
216
|
expect(result.stripped).toBe(1);
|
|
192
|
-
expect(result.markdown).
|
|
217
|
+
expect(result.markdown).not.toMatch(/data:image/);
|
|
218
|
+
expect(result.markdown).toMatch(/!\[|\[image/);
|
|
193
219
|
});
|
|
194
220
|
|
|
195
221
|
it('preserves remote image URLs', () => {
|